import { _decorator, Component, Node } from 'cc';
import { ProtoMgr } from '../Mangaers/ProtoMgr';
import EventMgr from '../Mangaers/EventMgr';
import NetMgr, { State } from '../Mangaers/NetMgr';
const { ccclass, property } = _decorator;
import msg from '../Msg/msgpb.js';
import UiManager from '../UI/UiManager';
import { plog } from '../Utils/Tools';
import { GameApp } from './GameApp';
const DefaultServer = msg.DeviceType.Unknown;//默认发送到的服务器类型
const TimeoutValue = 5000;//超时时间 毫秒

@ccclass('NetEventMgr')
export default class NetEventMgr extends Component {
    public static Instance: NetEventMgr = null;

    private msgMapReceive: Map<string, any>
    private isRelink = false
    private NodeUIBase: Node
    private NodeLinkCover: Node = null;
    private HeartIntervalId: number = -1;
    private CallbackConnect = null;
    // public IsLogin = false


    onLoad() {
        if (NetEventMgr.Instance === null) {
            NetEventMgr.Instance = this;
        }
        else {
            this.destroy();
            return;
        }
        this.NodeUIBase = this.node.getChildByName('NodeUI');
        this.msgMapReceive = new Map<string, any>();
        EventMgr.Instance.add_event_listenner("net_message", this, this.onRecvData);
        EventMgr.Instance.add_event_listenner("net_connect", this, this.onConnect);
        EventMgr.Instance.add_event_listenner("net_disconnect", this, this.onDisconnect);
        // EventMgr.Instance.add_event_listenner("net_register", this, this.onNetRegister);

        plog("pong 1", msg)
        plog("pong 2", msg.Pong.name)
        this.RegisterMsgReceive(msg.Pong.name, () => {
            plog("-----recevice heart -------------")
        })
    }

    //注册全局监听的消息
    public RegisterMsgReceive(msgName: string, funcOk: (mb: msg.BaseMessage) => void): void {
        if (!this.msgMapReceive.has(msgName)) {
            this.msgMapReceive.set(msgName, {
                Scene: 0,
                Temp: false,
                FuncOk: funcOk
            })
        }
    }
    //注册当前页面监听的消息
    private registerMsgReceiveTemp(msgName: string, funcOk: (mb: msg.BaseMessage) => void, funcErr: (mb: msg.BaseMessage) => void): void {
        if (!this.msgMapReceive.has(msgName)) {
            this.msgMapReceive.set(msgName, {
                Scene: GameApp.Instance.GetSceneState(),
                Temp: true,
                FuncOk: funcOk,
                FuncErr: funcErr
            })
        } else {
            console.error("msg recv:" + msgName + " is regitered!!!!")
        }
    }
    //注销消息
    public UnregisterMsg(msgName: string): void {
        if (this.msgMapReceive.has(msgName)) {
            this.msgMapReceive.delete(msgName);
        }
    }

    //调用消息处理回调函数
    public RunMsgReceiveFunc(mb: msg.BaseMessage): void {
        const msgName = mb.MsgName
        if (this.msgMapReceive.has(msgName)) {
            let obj = this.msgMapReceive.get(msgName)
            if (obj.Temp) {
                this.UnregisterMsg(msgName)
                this.RemoveCoverLink()
            }
            if (obj.Scene == 0 || obj.Scene == GameApp.Instance.GetSceneState()) {//判断是当前场景执行
                if (mb.Err) {
                    if (obj.FuncErr) {
                        obj.FuncErr(mb)
                    } else {
                        UiManager.Instance.ShowHint(this.NodeUIBase, mb.Err.Result, (pm) => { })
                    }
                } else {
                    obj.FuncOk(mb)
                }
            }
        }
    }

    //超时调用
    public RunTimeOut(nameA: string) {
        if (this.msgMapReceive.has(nameA)) {
            let mb = msg.BaseMessage.create();
            mb.MsgName = nameA
            mb.Err = msg.Error.create()
            mb.Err.Code = msg.ErrCode.Err_Timeout
            mb.Err.Result = "msg:" + nameA + " is timeout."
            this.RunMsgReceiveFunc(mb)
        }
    }

    //仅发送消息，不等回调
    public SendMessageOnly(nameR: string, dataR: Uint8Array, dest: msg.DeviceType = DefaultServer) {
        let buf = this.createMsgBuffToSend(nameR, dataR, dest)
        NetMgr.Instance.send_data(buf);
    }

    //发送消息，等回调处理
    public SendMessage(nameR: string, nameA: string, dataR: Uint8Array, callbackOk: (mb: msg.BaseMessage) => void, callbackErr: (mb: msg.BaseMessage) => void = null, dest: msg.DeviceType = DefaultServer): void {
        let buf = this.createMsgBuffToSend(nameR, dataR, dest)
        this.registerMsgReceiveTemp(nameA, callbackOk, callbackErr)
        setTimeout(() => {
            this.RunTimeOut(nameA)
        }, TimeoutValue);// 超时
        this.AddCoverLink()
        NetMgr.Instance.send_data(buf);
    }

    //把要发送的消息创建城BaseMessage的数据格式
    private createMsgBuffToSend(nameR: string, dataR: Uint8Array, dest: msg.DeviceType): any {
        let mb = msg.BaseMessage.create();
        mb.MsgName = nameR
        mb.MsgData = dataR
        let bs = msg.BaseMessage.encode(mb).finish()
        plog("++++++++ msg bytes ++++++ ", bs.buffer)
        return bs.buffer

        // let mcR = msg.MsgConfig.create()
        // mcR.Name = nameR
        // mcR.Source = msg.DeviceType.ClientUser
        // mcR.Dest = dest
        // let bsMcR = msg.MsgConfig.encode(mcR).finish()
        // let len0 = bsMcR.length;
        // let len1 = dataR.length;
        // let AllLen = len0 + len1 + 4;
        // // plog("len0 ", len0, "len1 ", len1, "AllLen", AllLen)
        // var buf = new ArrayBuffer(AllLen);
        // var dataview = new DataView(buf);
        // var uint8Buf = new Uint8Array(buf);
        // dataview.setInt16(0, len0, true);
        // uint8Buf.set(bsMcR, 2);
        // let end0 = len0 + 2
        // dataview.setInt16(end0, len1, true);
        // uint8Buf.set(dataR, end0 + 2);
        // plog("++++++++ msg bytes ++++++ ", buf)
        // return buf
    }

    //增加连接中的页面
    public AddCoverLink(): boolean {
        if (this.NodeLinkCover == null) {
            this.NodeLinkCover = UiManager.Instance.AddCover(this.NodeUIBase, 2, 500)
            return true
        }
        return false
    }


    //删除连接中的页面
    public RemoveCoverLink() {
        if (this.NodeLinkCover != null) {
            this.NodeLinkCover.removeFromParent()
            this.NodeLinkCover = null;
            return true
        }
        return false
    }

    //连接成功的回调
    public onConnect(uname, udata): void {
        if (this.HeartIntervalId === -1) {
            this.HeartIntervalId = setInterval(() => {
                let mr = msg.Ping
                let m = mr.create()
                this.SendMessageOnly(mr.name, mr.encode(m).finish())
            }, 30000)
        }
        if (this.CallbackConnect) {
            this.CallbackConnect()
            this.CallbackConnect = null;
        }
        this.RemoveCoverLink()
    }


    //开始连接，传入连接成功的回调
    public StartConnect(callback: () => void) {
        this.AddCoverLink()
        if (NetMgr.Instance.GetState() == State.Closed) {
            this.CallbackConnect = callback
            NetMgr.Instance.connect_to_server();
        } else {
            callback()
        }
    }

    //断开连接的回调
    public onDisconnect(uname, udata): void {
        if (!this.RemoveCoverLink()) {
            return
        }
        if (this.HeartIntervalId !== -1) {
            clearInterval(this.HeartIntervalId)
            this.HeartIntervalId = -1
        }
        if (!this.isRelink) {
            this.isRelink = true
            UiManager.Instance.ShowMsgBox(this.NodeUIBase, "断开连接，是否重连", (ok) => {
                this.isRelink = false
                if (ok) {
                    // this.StartConnect()
                }
            })
        }
    }

    // 收到服务器数据
    public onRecvData(uname, udata: ArrayBuffer): void {
        plog("接收返回", udata);
        // let dataView = new DataView(udata);
        // let uint8Buf: Uint8Array = new Uint8Array(udata);
        // let len0 = dataView.getInt16(0, true);
        // let end0 = 2 + len0
        // let bs0 = uint8Buf.subarray(2, end0);
        // let len1 = dataView.getInt16(end0, true);
        // let start1 = end0 + 2
        // let bs1 = uint8Buf.subarray(start1, start1 + len1);



        let uint8Buf: Uint8Array = new Uint8Array(udata);
        let mb = msg.BaseMessage.decode(uint8Buf);
        if (mb.MsgName !== 'Pong') {
            plog("rec msg base:", mb)
        }

        this.RunMsgReceiveFunc(mb)
    }

    update(deltaTime: number) {
    }


}
